<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
<style>
#box {
  background-color: rgba(40, 40, 190, 255);
  border: 4px solid rgb(20, 20, 120);
  transition: background-color 1s, border 1s;
  width: 350px;
  height: 350px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}

.vertical {
  color: white;
  font: 32px "Arial";
}

.extra {
  width: 350px;
  height: 350px;
  margin-top: 10px;
  border: 4px solid rgb(20, 20, 120);
  text-align: center;
  padding: 20px;
}
</style>
  <div id="box">
  <div class="vertical">
    Welcome to <strong>The Box!</strong>
  </div>
</div>
<script>
var numSteps = 20.0;

var boxElement;
var prevRatio = 0.0;
var increasingColor = "rgba(40, 40, 190, ratio)";
var decreasingColor = "rgba(190, 40, 40, ratio)";

// Set things up.

window.addEventListener("load", function(event) {
  boxElement = document.querySelector("#box");

  createObserver();
}, false);
function createObserver() {
  var observer;

  var options = {
    root: null,
    rootMargin: "0px",
    threshold: buildThresholdList()
  };

  observer = new IntersectionObserver(handleIntersect, options);
  observer.observe(boxElement);
}
function buildThresholdList() {
  var thresholds = [];

  for (var i=1.0; i<=numSteps; i++) {
    var ratio = i/numSteps;
    thresholds.push(ratio);
  }

  thresholds.push(0);
  return thresholds;
}
function handleIntersect(entries, observer) {
  entries.forEach(function(entry) {
    if (entry.intersectionRatio > prevRatio) {
      entry.target.style.backgroundColor = increasingColor.replace("ratio", entry.intersectionRatio);
    } else {
      entry.target.style.backgroundColor = decreasingColor.replace("ratio", entry.intersectionRatio);
    }

    prevRatio = entry.intersectionRatio;
  });
}

</script>
</body>
</html>
<!-- 
IntersectionObserver:浏览器原生提供的构造函数

用处:
1.页面滚动时图片懒加载
2.瀑布流
3.根据可视性决定对象是否执行动画

耗时进程Window.requestIdleCallback()
所有对象距离均按矩形计算

创建观察对象
var io = new IntersectionObserver(callback, option);
// 开始观察 观察多个对象,许多次调用
io.observe(document.getElementById('example'));

// 停止观察
io.unobserve(element);

// 关闭观察器
io.disconnect();

callback(entries) 目标元素的可见性变化时(刚进入,刚离开)
entries:[IntersectionObserverEntry,...]
IntersectionObserverEntry属性:
{
  time: 3893.92,//变化时间 ms
  rootBounds: ClientRect { //根元素矩形区域
    bottom: 920,
    height: 1024,
    left: 0,
    right: 1024,
    top: 0,
    width: 920
  },
  boundingClientRect: ClientRect { //目标元素区域
     // ...
  },
  intersectionRect: ClientRect { //目标元素与根元素交叉矩形
    // ...
  },
  intersectionRatio: 0.54, //目标元素可见比 完全可见为1
  target: element //被观察元素 DOM节点
}
Option 对象:
threshold:决定了什么时候触发回调函数。数组，成员是门槛值，默认为[0]，即交叉比例（intersectionRatio）达到0时触发回调函数。
root 属性，rootMargin 属性:祖先包含块!!! 扩展或缩小rootBounds这个矩形的大小，从而影响intersectionRect交叉区域的大小。它使用CSS的定义方法，比如10px 20px 30px 40px，表示 top、right、bottom 和 left 四个方向的值。

异步  应requestIdleCallback() 优先级低,空闲才执行

懒加载原理?
function query(selector) {
  return Array.from(document.querySelectorAll(selector));
}

var observer = new IntersectionObserver(
  function(changes) {
    changes.forEach(function(change) {
      var container = change.target;
      var content = container.querySelector('template').content;
      container.appendChild(content);
      observer.unobserve(container);
    });
  }
);

query('.lazy-loaded').forEach(function (item) {
  observer.observe(item);
});

无限滚动的实现
var intersectionObserver = new IntersectionObserver(
  function (entries) {
    // 如果不可见，就返回
    if (entries[0].intersectionRatio <= 0) return;
    loadItems(10);
    console.log('Loaded new items');
  });

// 开始观察
intersectionObserver.observe(
  document.querySelector('.scrollerFooter')
);
无限滚动时，最好在页面底部有一个页尾栏（又称sentinels）。一旦页尾栏可见，就表示用户到达了页面底部，从而加载新的条目放在页尾栏前面。这样做的好处是，不需要再一次调用observe()方法，现有的IntersectionObserver可以保持使用。

后台标签不渲染,便不检测
threshold:构造函数 和 thresholds:实例

计算相交区域大小
让 rect 为目标元素矩形
让 current 为目标元素的父元素
如果 current 不是根元素，则进行下面的循环：
如果 current 的 overflow 不是 visible（是 scroll 或 hidden 或 auto) 或者 current 是个 iframe 元素（iframe 天生自带 overflow: auto），则：
让 rect 等于 rect 和 current 的矩形（要排除滚动条区域）的交集
让 current 为 current 的父元素（iframe 里的 html 元素的父元素就是父页面里的 iframe 元素）
也就是说，实际上是顺着目标元素的 DOM 树一直向上循环求交集的过程
目标元素为0:0->(刚进入)1->(刚离开)0;
贴边时:注意0
 -->